/**
 * Copyright (c) 2009 blurredVision
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
 * associated documentation files (the "Software"), to deal in the Software without restriction, 
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or 
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 
 * NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT 
 * OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#ifndef __DX_EFFECT_H__
#define __DX_EFFECT_H__

#pragma once

#include <d3dx9.h>

#include <string>

#include "DXResource.h"
#include "IShaderEffect.h"
#include "IFile.h"
namespace directx {

class DXShaderInclude 
: public ID3DXInclude	// Handles include directives
{
public:
	DXShaderInclude() : file(NULL) {}
	virtual ~DXShaderInclude() {}
	 /// open an include file and read its contents
    STDMETHOD(Open)(D3DXINCLUDE_TYPE IncludeType, LPCSTR pFileName, LPCVOID pParentData, LPCVOID* ppData, UINT* pBytes);
    /// close an include file
    STDMETHOD(Close)(LPCVOID pData);
protected:
	IFile *file;

};

class DXShaderEffect
:	public IShaderEffect, 
	public DXResource
{
public:
	DXShaderEffect(void);
	~DXShaderEffect(void);

	bool load(const std::string &filename);

	bool bind(bool useBestValidTechnique = false);
	bool unbind();

	virtual bool beginPass(int pass=0);
	virtual bool endPass();

	bool setVariables();

	bool setTechnique(const std::string &technique);
	bool setTechnique(const SHADERHANDLE &handle);

	virtual bool setInt(const SHADERHANDLE &handle, int* ints, int size);
	virtual bool setFloat(SHADERHANDLE &handle, float* floats, int size);
	virtual bool setBoolean(const SHADERHANDLE &handle, const  bool* bools, int size);
	virtual bool setMatrix(const SHADERHANDLE &handle, math::Matrix4 *matrix);
	virtual bool setTexture(const SHADERHANDLE &handle, ITexture *tex);
	virtual bool setData(const SHADERHANDLE &handle, void* data, int numBytes);
	
	virtual void release();
	virtual void reset();

	// Adds a texture reference to the DXShaderEffect. This will be assigned by calling setVariables()
	virtual bool addTexture(const SHADERHANDLE &handle, ITexture* texture);

	virtual bool hasParameter(const std::string &identifier);

	virtual int*   getParameterValueAsIntArray(const std::string &identifier, int count = 1);
	virtual float* getParameterValueAsFloatArray(const std::string &identifier, int count = 1);

	virtual SHADERHANDLE getParameterByName(const std::string &identifier);

	virtual SHADERHANDLE getParameterBySemantic(const std::string &semantic);

	virtual bool setGlobalWorldTransformMatrix(math::Matrix4 *matrix);

	virtual bool beginParameterBlock();
	virtual SHADERHANDLE endParameterBlock();
	virtual void applyParameterBlock(SHADERHANDLE blockHandle);

private:
	// Handles must be checked after loading
	SHADERHANDLE recheckHandle(const SHADERHANDLE &handle);
	std::map<D3DXHANDLE, sEffectData> m_mData;

	std::string     sFilename;
	D3DXHANDLE      hWorld;
	D3DXHANDLE      hWorldInv;
	D3DXHANDLE      hWorldIT;
	D3DXHANDLE      hView;
	D3DXHANDLE      hViewInv;
	D3DXHANDLE      hProj;
	D3DXHANDLE      hViewProj;
	D3DXHANDLE		hViewProjInv;
	D3DXHANDLE      hWorldView;
	D3DXHANDLE      hWorldViewProj;
	D3DXHANDLE		hWorldViewIT;
	D3DXHANDLE		hCameraPos;
	D3DXHANDLE		hTime;
	D3DXHANDLE		hLight0;

	D3DXHANDLE		hGlobalWorldTransform;		///< The shader handle for the world transform matrix for the global shader

	LPD3DXEFFECT	pDXEffect;

	std::map<SHADERHANDLE, std::string> orignames;	///< References to the original names of handles
	int				iVerifiedHandles;
	int				iRequestedHandles;
	float time;
};

} // namespace

#endif
